import re

from django import http
from django.contrib.auth import login, authenticate
from django.db import DatabaseError
from django.shortcuts import render, redirect
from django.urls import reverse
from django.views import View

from apps.users.models import User
from utils.response_code import RETCODE


class RegisterView(View):
    def get(self, request):
        """
        显示注册页面
        :param request: 请求对象
        :return: 注册页面
        """
        return render(request, 'register.html')

    def post(self, request):
        """
        用户注册
        :param request: 请求对象
        :return: 注册成功
        """
        # 1 获取数据
        # 这是form表单数据，所以用request.POST.get('')获取数据, 非form表单用body
        username = request.POST.get('username')
        password = request.POST.get('password')
        password2 = request.POST.get('password2')
        mobile = request.POST.get('mobile')
        allow = request.POST.get('allow')
        # 获取参数完毕

        # 2 校验数据
        # 参数是否齐全
        if not all([username, password, password2, mobile, allow]):
            return http.HttpResponseBadRequest('缺少必传参数')
        # 用户名是否是5到20个字符
        if not re.match(r'^[a-zA-Z0-9_]{5,20}$', username):
            return http.HttpResponseBadRequest('用户名必须是5~20字符')
        # 密码是否是8到20位字符
        if not re.match(r'^[a-zA-Z0-9]{8,20}$', password):
            return http.HttpResponseBadRequest('密码必须是8~20个字符')
        # 判断两次密码是否相等
        if password != password2:
            return http.HttpResponseBadRequest('两次输入密码不一致')
        # 判断手机号码是否符合
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return http.HttpResponseBadRequest('手机号码格式不符')
        # 判断用户是否勾选协议
        if allow != 'on':
            return http.HttpResponseBadRequest('请勾选用户协议')

        # 3 保存数据到数据库
        try:
            user = User.objects.create_user(username=username, password=password, mobile=mobile)
        except DatabaseError:
            return render(request, 'register.html', {'register_errmsg': '注册失败'})  # 只有用户名相同才会显示在注册页面
        login(request, user)
        # 4 返回响应结果
        return redirect(reverse('index:index'))


class UsernameCountView(View):
    def get(self, request, username):
        """
        用户名重复，
        :param request: 请求对象
        :param username: 用户名
        :return: JSON
        """
        # 查询数据库中的用户名是否等于传过来的用户名
        count = User.objects.filter(username=username).count()
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK', 'count': count})  # JSON格式返回字典形式


class MobileCountView(View):
    def get(self, request, mobile):
        """
        手机号重复注册
        :param request: 请求对象
        :param mobile: 传入的手机号码
        :return: JSON
        """
        count = User.objects.filter(mobile=mobile).count()
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK', 'count': count})


class LoginView(View):
    def get(self, request):
        """
        显示登录页面
        :param request: 请求对象
        :return: 登录页面
        """
        return render(request, 'login.html')

    def post(self, request):
        """
        实现登录逻辑
        :param request: 请求对象
        :return:登录成功
        """
        # 获取参数
        username = request.POST.get('username')
        password = request.POST.get('password')
        remembered = request.POST.get('remembered')
        # 校验数据
        # 判断数据是否齐全
        if not all([username, password]):
            return http.HttpResponseBadRequest('缺少必传参数')
        # 判断用户名是否是5~20个字符
        if not re.match(r'^[a-zA-Z0-9_]{5,20}$', username):
            return render(request, 'login.html', {'account_errmsg': '请输入正确的用户名或者手机号'})
        # 判断密码是否正确
        if not re.match(r'^[a-zA-Z0-9]{8,20}', password):
            return render(request, 'login.html', {'account_errmsg': '密码最少8位，最长20位'})

        # 认证用户登录
        user = authenticate(username=username, password=password)
        if user is None:
            return render(request, 'login.html', {'account_errmsg': '用户名或者密码错误'})

        # 实现状态保持
        login(request, user)
        # 实现状态保持的周期
        if remembered != 'on':
            # 没有记住用户，浏览器结束就过期
            request.session.set_expiry(0)
        else:
            # None表示两周后过期
            request.session.set_expiry(None)

        # 返回登录结果
        return redirect(reverse('index:index'))
